#include <QDesktopServices>
#include <QtGui/QApplication>
#include <QtGui/QMessageBox>
#include <QtCore/qtextcodec.h>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>
#include <QResource>
#include <qinputdialog.h>
//---- libmyqq --
#include "qqclient.hpp"
#include "buddy.hpp"
#include "qun.hpp"
#include "group.hpp"
#include "memory.hpp"
#include "utf8.hpp"
#include "config.hpp"
#include "qtq_config.h"
#include "qqsocket.hpp"
#include <stdio.h>
#include "debug.hpp"
#ifdef __WIN32__
#include <conio.h>
#include <winsock.h>
#include <wininet.h>
#include <windows.h>
#else
//#include <termios.h> //read password
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#endif
//---- qt --
#include "mainwindow.h"
#include "buddychat.h"
#include "login.h"
#include "db.h"
//---- qt --
#include <pthread.h>
#ifdef __GCCE__
#include<staticlibinit_gcce.h>
#endif

#define MSG need_reset = 1; setcolor( color_index ); printf


void *print_buf;

qqclient* qq = NULL;

bool isLoginSuccess = false;
bool isLoginCancel = false;
static int need_reset, no_color = 0;
enum{
        CMD_EXIT = 0, CMD_EXIT2,
        CMD_SAY, CMD_SAY2,
        CMD_TO, CMD_TO2,
        CMD_HELP,
        CMD_STATUS,
        CMD_ENTER, CMD_ENTER2,
        CMD_LEAVE, CMD_LEAVE2,
        CMD_WHO, CMD_WHO2,
        CMD_VIEW, CMD_VIEW2,
        CMD_QUN, CMD_QUN2,
        CMD_INFO, CMD_INFO2,
        CMD_UPDATE, CMD_UPDATE2,
        CMD_CHANGE, CMD_CHANGE2,
        CMD_TEST,
        CMD_VERIFY, CMD_VERIFY2,
        CMD_ADD, CMD_ADD2,
        CMD_DEL,
        CMD_CLS, CMD_CLS2, CMD_CLS3
};
//---- libmyqq --


MainWindow* wMain;
Login* wLogin;


#ifdef __WIN32__
#define _TEXT to_gb_force
static char* to_gb_force( char* s )
{
//	memset( print_buf, 0, PRINT_BUF_SIZE );
        utf8_to_gb( s, (char*)print_buf, PRINT_BUF_SIZE-1 );
        return (char*)print_buf;
}
static char* to_utf8( char* s )
{
//	memset( print_buf, 0, PRINT_BUF_SIZE );
        gb_to_utf8( s, (char*)print_buf, PRINT_BUF_SIZE-1 );
        return (char*)print_buf;
}

#else
#define _TEXT
#endif
char* mode_string( int mode )
{
        switch( mode ){
        case QQ_ONLINE:
                return "Online";
        case QQ_AWAY:
                return "Away";
        case QQ_BUSY:
                return "Busy";
        case QQ_OFFLINE:
                return "Offline";
        case QQ_HIDDEN:
                return "Hidden";
        case QQ_KILLME:
                return "Kill Me";
        case QQ_QUIET:
                return "Quiet";
        }
        return "Unknown";
}
char* myqq_get_buddy_name( qqclient* qq, uint uid )
{
        static char tmp[16];
        qqbuddy* b = buddy_get( qq, uid, 0 );
        if( b )
                return b->nickname;
        if( uid == 10000 )
                return "System";
        if( uid != 0 ){
                sprintf( tmp, "%u" , uid );
                return tmp;
        }
        return "Nobody";
}
static char* myqq_get_qun_name( qqclient* qq, uint uid )
{
        static char tmp[16];
        qqqun* q = qun_get( qq, uid, 1 );
        if( q )
                return q->name;
        if( uid != 0 ){
                sprintf( tmp, "%u" , uid );
                return tmp;
        }
        return "[q==NULL]";
}

int myqq_send_im_to_qun( qqclient* qq, uint int_uid, char* msg, int wait )
{
        char tmp[MSG_CONTENT_LEN];
        pack_faces(msg,tmp,MSG_CONTENT_LEN);
        qun_send_message( qq, int_uid, tmp );
        if( wait )
        {
                if( qqclient_wait( qq, 15 ) < 0 )
                        return -1;
        }
        return 0;
}
int myqq_send_im_to_buddy( qqclient* qq, uint int_uid, char* msg, int wait )
{
        char tmp[MSG_CONTENT_LEN];
        pack_faces(msg,tmp,MSG_CONTENT_LEN);
        buddy_send_message( qq, int_uid, tmp );
        if( wait )
        {
                if( qqclient_wait( qq, 15 ) < 0 )
                        return -1;
        }
        return 0;
}

int myqq_get_buddy_info( qqclient* qq, uint uid, char* buf, int size )
{
#ifndef NO_BUDDY_DETAIL_INFO
        qqbuddy *b = buddy_get( qq, uid, 0 );
        if( size < 256 )
                return -1;
        if( b == NULL )
                return -2;
        int len, ip = htonl(b->ip);
        len = sprintf( buf,     "好友昵称\t%-32s\n"
                                "用户账号\t%-32d\n"
                                "IP地址\t\t%-32s\n"
                                "IP端口\t\t%-32d\n"
                                "头像\t\t%-32d\n"
                                "年龄\t\t%-32d\n"
                                "性别\t\t%-32s\n"
                                "状态\t\t%-32s\n",
                b->nickname, b->number, inet_ntoa( *(struct in_addr*)&ip ), b->port, b->face, b->age,
                (b->sex==0x00)?"Male": (b->sex==0x01)?"Female":"Asexual", mode_string(b->status) );
        return len;
#endif
}


//Note: this function change the source string directly.
char* util_escape( char* str )
{
        unsigned char* ch;
        ch = (unsigned char*)str;
        while( *ch )
        {
                if( *ch < 0x80 ) //ASCII??
                {
                        if( !isprint(*ch) ) //if not printable??
                                *ch = ' ';	//use space instead..
                        ch ++;	//skip one
                }else{
                        ch +=2; //skip two
                }
        }
        return str;
}

/*   The output buf looks like this:
L8bit  L16bit        L16bit        L32bit
1      357339036     online		Xiao xia
2      273310179     offline	Huang Guan
*/
//Note: size must be big enough
static int myqq_get_buddy_list( qqclient* qq, char* buf, int size, char online )
{
        int i, len = 0;
        //avoid editing the array
        buf[0] = 0;
        pthread_mutex_lock( &qq->buddy_list.mutex );
        int ln = 1;
        for( i=0; i<qq->buddy_list.count; i++ )
        {
                qqbuddy * b = (qqbuddy*)qq->buddy_list.items[i];
                if( online && b->status == QQ_OFFLINE ) continue;
                len = sprintf( buf, "%s%-8d%-16d%-16s%-16.64s\n", buf, ln ++, b->number,
                        mode_string( (int) b->status ), util_escape( b->nickname ) );
                if( len + 80 > size ) break;
        }
        pthread_mutex_unlock( &qq->buddy_list.mutex );
        return len;
}

/*   The output buf looks like this:
L8bit  L16bit        L16bit        L32bit
1      467788923     12118724	Xinxing Experimental School
2      489234223     13223423	SGOS2007
*/
//Note: size must be big enough
static int myqq_get_qun_list( qqclient* qq, char* buf, int size )
{
        int i, len = 0, ln=1;
        //avoid editing the array
        buf[0] = 0;
        pthread_mutex_lock( &qq->qun_list.mutex );
        for( i=0; i<qq->qun_list.count; i++ )
        {
                qqqun * q = (qqqun *)qq->qun_list.items[i];
                len = sprintf( buf, "%s%-8d%-16d%-16d%-16.64s\n", buf, ln ++, q->number,
                        q->ext_number, util_escape( q->name ) );
                if( len + 80 > size ) break;
        }
        pthread_mutex_unlock( &qq->qun_list.mutex );
        return len;
}

/*   The output buf looks like this:
L8bit  L16bit        L16bit        L32bit
1      357339036     Manager	Xiaoxia
2      273310179     Fellow		Huang Guan
*/
//Note: size must be big enough
static int myqq_get_qun_member_list( qqclient* qq, uint int_uid, char* buf, int size, char online )
{
        qqqun * q = qun_get( qq, int_uid, 0 );
        if( !q )return 0;
        //Hope the Qun won't get removed while we are using it.
        int i, len = 0, ln = 1;
        buf[0] = 0;
        pthread_mutex_lock( &q->member_list.mutex );
        for( i=0; i<q->member_list.count; i++ )
        {
                qunmember * m = (qunmember *)q->member_list.items[i];
                if( online && m->status == QQ_OFFLINE ) continue;
                len = sprintf( buf, "%s%-8d%-16d%-16s%-16.64s\n", buf, ln++, m->number,
                        (m->role&1)?"Admin":"Fellow", util_escape( m->nickname ) );
                if( len + 80 > size )
                        break;
        }
        pthread_mutex_unlock( &q->member_list.mutex );
        return len;
}

//interface for getting qun information
/* Output style:
*/
static int myqq_get_qun_info( qqclient* qq, uint int_uid, char* buf, int size )
{
        char cate_str[4][10] = {"Classmate", "Friend", "Workmate", "Other" };
        qqqun *q = qun_get( qq, int_uid, 0 );
        if( !q )return 0;
        int len;
        if( size < 256 )
                return -1;

        if( q == NULL )
                return -2;
        len = sprintf( buf, 	"名称\t\t%-32s\n"
                                "内部号码\t%-32d\n"
                                "群号码\t\t%-32d\n"
                                "群类型\t\t%-32s\n"
                                "是否允许加入\t%-32s\n"
                                "群分类\t\t%-32s\n"
                                "创建人\t\t%-32d\n"
                                "成员数量\t%-32d\n"
                                "群的简介\n%-32s\n"
                                "群的公告\n%-32s\n",
                q->name, q->number, q->ext_number, (q->type==0x01)?"Normal":"Special",
                (q->auth_type==0x01)?"No": (q->auth_type==0x02)?"Yes":
                        (q->auth_type==0x03)?"RejectAll":"Unknown",
                q->category > 3 ? cate_str[3] : cate_str[(int)q->category],
                q->owner, q->member_list.count, q->intro, q->ann );
        return len;
}
void buddy_changestatus_callback ( qqclient* qq, qqbuddy* b,int lastStatus )
{
    if(wMain)
    {
        wMain->ChangeStatus(b,lastStatus);
    }
}

void buddy_msg_callback ( qqclient* qq, uint uid, time_t t, char* msg )
{
        char timestr[24];
        struct tm * timeinfo;
        void* str;
        int len;
        timeinfo = localtime ( &t );
        strftime( timestr, 24, "%Y-%m-%d %H:%M:%S", timeinfo );
        len = strlen( msg );
        NEW( str, len+64 );
        if( uid == 10000 ){
                sprintf( (char*)str, "broadcast^$System^$%s", msg );

        }else{
                sprintf( (char*)str, "buddymsg^$%u^$%s^$%s", uid, timestr, msg );
        }
        //QString info = QObject::tr("调试:") + QObject::tr((char*)str);

        DBG_QS(  QObject::tr("调试:") + QObject::tr((char*)str) );

        STR_inforecord record;
        record.type = 0;
        record.fromid = uid;
        record.toid = qq->number;
        record.toqunid = 0;
        record.time = t;
        record.info = QString::fromUtf8( msg );

        db &infoDB = db::GetInstance();
        infoDB.pushRecord(0, uid, record);


        if(uid  == 0)
        {
            if(wMain)
                wMain->EmitSysMSG();
        }
        else
        {
            if((buddychatWin) && (buddychatWin->isVisible()) && (buddychatWin->UidIsTalking(uid, 0)) /*&& QApplication::activeWindow() == buddychatWin*/)
            {
                buddychatWin->EmitMSG();
            }
            else
            {
                if(wMain)
                    wMain->EmitMSG();
            }
        }

        DBG("buddy_msg_callback end");
        //qqclient_put_message( qq, (char*)str );
}


void qun_member_callback( qqclient* qq, qqqun* q, qunmember* m )
{
    STR_qunmember qm;
    qm.qid = q->number;
    qm.m = m;
    db &infoDB = db::GetInstance();
    infoDB.pushMemberInfo(qm);
}

void qun_msg_callback ( qqclient* qq, uint uid, uint int_uid,
        time_t t, char* msg )
{
        qqqun* q;
        char timestr[24];
        struct tm * timeinfo;
        void* str;
        int len;
        timeinfo = localtime ( &t );
        strftime( timestr, 24, "%Y-%m-%d %H:%M:%S", timeinfo );
        q = qun_get( qq, int_uid, 1 );
        if( !q ){
                //DBG("error: q=NULL");
                return;
        }
        len = strlen( msg );
        NEW( str, len+64 );
        sprintf( (char*)str, "clustermsg^$%u^$%u^$%s^$%s", q->ext_number, uid, timestr, msg );

        DBG_QS( QObject::tr("调试:") + QObject::tr((char*)str) );

        STR_inforecord record;
        record.type = 1;
        record.fromid = uid;
        record.toid = 0;
        record.toqunid = q->number ;
        record.time = t;
        record.info = QString::fromUtf8( msg );

        db &infoDB = db::GetInstance();

        infoDB.pushRecord(1, q->number, record);

        if((buddychatWin) && (buddychatWin->isVisible()) && (buddychatWin->UidIsTalking(q->number, 1)) /*&& QApplication::activeWindow() == buddychatWin*/)
        {
            buddychatWin->EmitMSG();
        }


        //qqclient_put_message( qq, (char*)str );
}

int main(int argc, char *argv[])
{

    srand(time(NULL));
    config_init();
    DBG( "qqsocket_init_start()" );
    qqsocket_init();
    DBG( "qqsocket_init_ok()" );

    DBG( "momery alloc()" );

    NEW( print_buf, PRINT_BUF_SIZE );
    void* qqbufer;
    NEW( qqbufer, sizeof(qqclient) );
    qq = (qqclient*)qqbufer;
    if(!print_buf || !qq ){
            //MSG("no enough memory.");
            QMessageBox::critical(0,"critical","no enough memory.");
            return -1;
    }
    DBG( "QApplication()" );
    QApplication app(argc, argv);
    //a.setQuitOnLastWindowClosed(false);

    DBG_QS( "app.styleSheet()"+app.styleSheet() );
    app.setStyleSheet("QLineEdit \
        { \
                    color: rgb(0, 0, 0); \
                    background-color: rgb(255, 255, 255); \
        } \
        QListWidget{ \
                     color: rgb(0, 0, 0); \
                     background-color: rgba(255, 255, 255, 50%); \
                     } \
        QListView{ \
             color: rgb(0, 0, 0); \
             background-color: rgba(255, 255, 255, 50%); \
             } \
        QPushButton{ \
                    border-style: none; \
                    border-width: 0px; \
    }");
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf8"));
    QTextCodec::setCodecForCStrings(QTextCodec::codecForName("utf8"));
    QTextCodec::setCodecForTr( QTextCodec::codecForName("utf8") );

    QResource::registerResource("./qtq.rcc");

    QPalette pa;
    pa.setColor(QPalette::WindowText,Qt::black);

    wMain = new MainWindow();
    wLogin = new Login(wMain);
    QObject::connect(wLogin,SIGNAL(LoginSuccess()),wMain,SLOT(onLoginSuccess()));

#ifdef __SYMBIAN32__
    wMain->showFullScreen();
    wLogin->showFullScreen();
#else
    wMain->show();
    wLogin->show();
#endif
    app.setActiveWindow(wLogin);
    bool r = app.exec();
    if(qq)
    {
        qqclient_logout( qq );
        qqsocket_end();


        if(qq->process != P_INIT )
        {
            qqclient_cleanup( qq );
        }
    }
    config_end();
    DEL( qq );
    memory_end();

    return r;
}
